# -*- coding:utf-8 -*-
import json
import os
import random
import sys
import textwrap

import requests

# @Time    : 2023/8/31 13:54
# @Author  : zengwenjia
# @Email   : zengwenjia@lingxi.ai
# @File    : sales.py
# @Software: LLM_internal

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
from bot.bot import Bot
from loguru import logger
import asyncio
from common import constants
from bot.insurance_consultant_simple.agent.user_questioning import QuestioningDisputeResolution
from bot.insurance_consultant_simple.agent.conversation_agent import Conversation
from bot.insurance_consultant_simple.knowledge_question_solution.knowledge_embedding import \
    AZUREQuery as QuestionSolutionAZUREQuery
from bot.insurance_consultant_simple.knowledge_sales_skill.knowledge_embedding import AZUREQuery as SalesSkillAZUREQuery
from bot.insurance_consultant_simple.agent.sales_sop_agent import SalesSop
from bot.insurance_sales_gpt.demo.cache_dict import cache_dict
import tiktoken

logger.add("./log/短险执行日志_{time}.log", retention="1 days")


class Sales(Bot):
    """销售机器人"""

    knowledge_question_solution_query = QuestionSolutionAZUREQuery()
    knowledge_question_solution_query.load_knowledge_base()

    knowledge_sale_skill_query = SalesSkillAZUREQuery()
    knowledge_sale_skill_query.load_knowledge_base()

    def __init__(self):
        self.user_info = ''
        self.solution = ""
        self.max_token_length = 1024 * 3
        self.role_name = "保险规划师"
        self.business_background = """保险公司:泰康保险
赠险产品:交通意外险
销售产品:百万医疗险(限时权益:体检卡、家庭赠险、在线问诊、重疾绿通)
赠险领取方式:通过"如果有保"公众号"""
        self.model_name = "gpt"
        self.user_job = ''
        self.process_knowledge = ''
        self.multi_knowledge = ''
        self.user_question = ''
        self.skill = ''
        self.sop = ''
        self.content = ''
        self.underwriting = ''
        self.count_token = 0
        self.max_agent_token = 0

    def get_token_count(self, input_str, res_str):
        env = tiktoken.encoding_for_model('gpt-4')
        return len(env.encode(input_str + res_str))

    def format_conversation_history(self, conversation_context, max_token_length=None):
        dialogue_history = ""
        if (not max_token_length) or (max_token_length > self.max_token_length):
            max_token_length = self.max_token_length
        # 倒序遍历record_list
        for record in conversation_context[::-1]:
            next_dialogue_history = dialogue_history
            if record['role'] == constants.ROLE_USER:
                next_dialogue_history = "用户:" + record["content"] + "\n" + dialogue_history
            elif record['role'] == constants.ROLE_ASSISTANT:
                next_dialogue_history = self.role_name + ":" + record["content"] + "\n" + dialogue_history
            if len(next_dialogue_history) > max_token_length:
                break
            else:
                dialogue_history = next_dialogue_history
        return dialogue_history

    async def get_user_question(self):
        try:
            questioning_dispute_resolution = QuestioningDisputeResolution(self.role_name, self.conversation_history_str,
                                                                          self.user_base_info)
            self.user_question = await questioning_dispute_resolution.achat_auto_llm(type=self.model_name)
            token_size = self.get_token_count(questioning_dispute_resolution.prompt, self.user_question)
            self.count_token = self.count_token + token_size
            if token_size > self.max_agent_token:
                self.max_agent_token = token_size
            logger.info(
                f"session_id:{self.session_id},content:{self.content},agent-用户疑义是:{self.user_question},本次消耗token:{token_size}")
        except Exception as e:
            # 打印错误的堆栈信息
            logger.exception(e)
            self.user_question = ""
        if self.user_question not in ('用户无问题', '用户无问题。'):
            # 查询用户疑问知识库
            knowledges = self.knowledge_question_solution_query.search_with_score(self.user_question, top_k=6,
                                                                                  limit_score=1.2)
            self.solution = "\n".join(knowledge.metadata.get('text') for knowledge in knowledges)

    async def get_sales_sop(self):
        """
        销售流程
        判断下一步的销售流程节点
        """
        try:
            sales_sop = SalesSop(self.role_name, self.conversation_history_str)
            self.sop = await sales_sop.achat_auto_llm(type=self.model_name)
            token_size = self.get_token_count(sales_sop.prompt, self.sop)
            self.count_token = self.count_token + token_size
            if token_size > self.max_agent_token:
                self.max_agent_token = token_size
            logger.info(
                f"session_id:{self.session_id},content:{self.content},agent-销售流程节点是:{self.sop},本次消耗 token:{token_size}")
        except Exception as e:
            # 打印错误的堆栈信息
            logger.exception(e)
            self.sop = ""
        # 查询销售流程知识库
        res = self.knowledge_sale_skill_query.search_with_score(self.sop, top_k=5, limit_score=0.8)
        for r in res:
            self.skill = self.skill + r.metadata.get('text') + "\n"

    async def generate_reply(self):
        """
        查询用户疑问解答话术 以及当前节点销售流程话术 并生成最终话术
        """
        try:
            conversation = Conversation(self.role_name,
                                        self.business_background,
                                        self.conversation_history_str, self.user_question, self.solution,
                                        self.sop,
                                        self.skill,
                                        self.user_job,
                                        self.underwriting)
            result = await conversation.achat_auto_llm(type=self.model_name)
            token_size = self.get_token_count(conversation.prompt, result)
            self.count_token = self.count_token + token_size
            if token_size > self.max_agent_token:
                self.max_agent_token = token_size
            if token_size > self.max_agent_token:
                self.max_agent_token = token_size
            logger.info(
                f"session_id:{self.session_id},content:{self.content},agent-话术生成是:{result},本次消耗token是:{token_size}")
            logger.info(
                f"session_id:{self.session_id},本轮对话单个agent消耗最大的token数为{self.max_agent_token},所有agent总共消耗token:{self.count_token}")
            return result
        except Exception as e:
            logger.exception(e)
            return "出错了，我不知道怎么回答你的问题，你可以换个问法试试"

    async def async_reply(self, context, session_id, name='王先生',
                          user_base_info='性别:男\n年龄:37\n城市:包头\n打开页面激活码:812915', content=''):
        conversation = self.format_conversation_history(context)
        # logger.info("conversation is " + str(conversation) + " session_id is " + str(session_id))
        self.session_id = session_id
        self.context = context
        self.conversation_history_str = conversation
        self.user_base_info = user_base_info
        self.content = content
        if f'cache_user_info:{session_id}' in cache_dict:
            self.user_info = cache_dict[f'cache_user_info:{session_id}']
        if len(self.context) > 1:
            # 用户疑义\销售流程
            user_question_task = asyncio.create_task(self.get_user_question())
            sales_sop_task = asyncio.create_task(self.get_sales_sop())
            await asyncio.gather(user_question_task, sales_sop_task)
        else:
            self.background_knowledge = ""
            self.skill = f"哎，您好。哎，您终于接电话了，看到您在泰康有个免费意外险已经领取成功了，但是保单一直没有收到，这样日后也就没办法理赔了，来电也是特意提醒您，稍后会把保单通过短信发给您，您注意查收下好吧？"
            self.solution = ""
        result = await self.generate_reply()
        # i = random.randint(0, 200)
        # if i < len(result):
        #     result = result[:i]
        logger.warning(f"session_id:{self.session_id},最终生成话术是:{result}")
        cache_dict[f'cache_user_info:{session_id}'] = self.user_info
        logger.info(f"---------------分割线--------------")
        return result


def send_message_to_wechat_group(content):
    webhook_url = 'https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=46a11f7d-4bdc-4092-a04c-9118f7b3d412'
    headers = {'Content-Type': 'application/json'}
    data = {
        "msgtype": "markdown",
        "markdown": {
            "content": content,
        }
    }
    dumps = json.dumps(data, ensure_ascii=False).replace('<br>', r'\n\n')
    response = requests.post(
        url=webhook_url,
        headers=headers,
        data=dumps.encode('utf-8')
    )


class SaleGPT:
    def reply(self, query, session_id=None, user_base_info=None):
        if session_id not in cache_dict:
            cache_dict[session_id] = []
        conversation_history = cache_dict.get(session_id)
        if len(conversation_history) > 0:
            conversation_dict = {}
            conversation_dict["role"] = "user"
            conversation_dict["content"] = query
            cache_dict[session_id].append(conversation_dict)

        sales = Sales()
        if user_base_info:
            sales.user_base_info = user_base_info
        result = asyncio.run(sales.async_reply(conversation_history, session_id, content=query))
        conversation_dict = {}
        conversation_dict["role"] = "assistant"
        conversation_dict["content"] = result
        cache_dict[session_id].append(conversation_dict)
        return result


def format_conversation_history(conversation_context):
    dialogue_history = []
    for record in conversation_context:
        if record['role'] == constants.ROLE_USER:
            dialogue_history.append('<font color="warning">用户:' + record["content"] + '</font>')
        elif record['role'] == constants.ROLE_ASSISTANT:
            dialogue_history.append('<font color="info">保险销售员:' + record["content"] + '</font>')
    return '<br>'.join(dialogue_history)


if __name__ == '__main__':
    conversation_history = []

    user_input = ''
    while True:
        sales = Sales()
        result = asyncio.run(sales.async_reply(conversation_history, "123", content=user_input))
        conversation_dict = {}
        conversation_dict["role"] = "assistant"
        conversation_dict["content"] = result
        conversation_history.append(conversation_dict)
        logger.info('历史对话缓存:{}'.format(conversation_history))
        if '再见' in result or '祝您生活愉快' in result:
            history = format_conversation_history(conversation_history)
            wraps = textwrap.wrap(history, 3900)
            for wrap in wraps:
                send_message_to_wechat_group(wrap)
            break
        user_input = input("请输入用户的对话：")
        conversation_dict = {}
        conversation_dict["role"] = "user"
        conversation_dict["content"] = user_input
        conversation_history.append(conversation_dict)
